package com.bckj.fastboot.security.component;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.bckj.fastboot.core.extra.cache.CacheOps;
import com.bckj.fastboot.security.constant.SecurityCacheConstants;
import com.bckj.fastboot.security.constant.SecurityConstants;
import com.bckj.fastboot.security.service.FastUserDetailsProvider;
import com.bckj.fastboot.upms.api.dto.ClientAuthInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;

import java.time.Duration;
import java.util.Arrays;
import java.util.Optional;

@Slf4j
@RequiredArgsConstructor
public class FastRegisteredClientRepository implements RegisteredClientRepository {

    private final FastUserDetailsProvider oauthDetailsProvider;
    private final CacheOps cacheOps;

    @Override
    public void save(RegisteredClient registeredClient) {

    }

    @Override
    public RegisteredClient findById(String id) {
        throw new UnsupportedOperationException();
    }

    @Override
    public RegisteredClient findByClientId(String clientId) {
        return loadRegisteredClient(clientId);
    }

    /**
     * 加载注册的客户端
     * @param clientId 客户端id
     */
    private RegisteredClient loadRegisteredClient(String clientId) {
        ClientAuthInfo clientDetails = cacheOps.cacheLocal(() -> {
            return oauthDetailsProvider.getClientDetails(clientId);
        }, SecurityCacheConstants.CLIENT_CACHE_NAME, SecurityCacheConstants.CLIENT_DETAILS_KEY);
        Assert.notNull(clientDetails, "客户端不存在clientId=" + clientId);
        RegisteredClient.Builder builder = RegisteredClient.withId(clientDetails.getClientId())
                .clientId(clientDetails.getClientId())
                .clientSecret(SecurityConstants.NOOP + clientDetails.getClientSecret())
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
        for (String authorizedGrantType : StrUtil.split(clientDetails.getAuthorizedGrantTypes(), ",")) {
            builder.authorizationGrantType(new AuthorizationGrantType(authorizedGrantType));
        }
        // 回调地址
        Optional.ofNullable(clientDetails.getWebServerRedirectUri())
                .ifPresent(redirectUri -> Arrays.stream(redirectUri.split(StrUtil.COMMA))
                        .filter(StrUtil::isNotBlank)
                        .forEach(builder::redirectUri));

        // scope
        Optional.ofNullable(clientDetails.getScope())
                .ifPresent(scope -> Arrays.stream(scope.split(StrUtil.COMMA))
                        .filter(StrUtil::isNotBlank)
                        .forEach(builder::scope));

        return builder
                .tokenSettings(TokenSettings.builder()
                        .accessTokenFormat(OAuth2TokenFormat.REFERENCE)
                        .accessTokenTimeToLive(Duration.ofSeconds(clientDetails.getAccessTokenValidity()))
                        .refreshTokenTimeToLive(Duration.ofSeconds(clientDetails.getRefreshTokenValidity()))
                        .build())
                .clientSettings(ClientSettings.builder()
                        .requireAuthorizationConsent(!BooleanUtil.toBoolean(clientDetails.getAutoApprove()))
                        .build())
                .build();
    }
}
